home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue50 / Alfresco / AABinTre.pas next >
Encoding:
Pascal/Delphi Source File  |  1999-09-04  |  36.2 KB  |  1,160 lines

  1. {*********************************************************}
  2. {* AABinTre                                              *}
  3. {* Copyright (c) Julian M Bucknall 1998-1999             *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco binary tree unit                  *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AABinTre;
  14.  
  15. interface
  16.  
  17. uses
  18.   SysUtils;
  19.  
  20. {$IFOPT D+}
  21. {$DEFINE InDebugMode}
  22. {$ENDIF}
  23.  
  24. {$DEFINE UseNodeManager}
  25.  
  26. const
  27.   PageNodeCount = 30;
  28.  
  29. type
  30.   TaaCompareFunction = function (aItem1, aItem2 : pointer) : integer;
  31.  
  32. const
  33.   aaLeft  = true;
  34.   aaRight = false;
  35.   aaRed   = true;
  36.   aaBlack = false;
  37.  
  38. type
  39.   TaaBinaryTree = class;     {forward declaration}
  40.  
  41.   TaaTraversalMode = (       {different traversal modes..}
  42.          tmPreOrder,         {..pre-order}
  43.          tmInOrder,          {..in-order}
  44.          tmPostOrder,        {..post-order}
  45.          tmLevelOrder);      {..level-order}
  46.  
  47.   PaaBTNode = ^TaaBTNode;    {binary tree node}
  48.   TaaBTNode = packed record
  49.     btParent : PaaBTNode;
  50.     btChild  : array [boolean] of PaaBTNode;
  51.     btData   : pointer;
  52.     case boolean of
  53.       false : (btExtra  : longint);
  54.       true  : (btColor  : boolean);
  55.   end;
  56.  
  57.   TaaDisposeItem = procedure (aItem : pointer);
  58.     {-procedure prototype to dispose of an item}
  59.  
  60.   TaaProcessNode = function (aNode      : PaaBTNode;
  61.                              aExtraData : pointer) : boolean;
  62.     {-function prototype to process a node}
  63.  
  64.   TaaBinaryTree = class           {binary tree class}
  65.     private
  66.       FCount   : integer;
  67.       FDispose : TaaDisposeItem;
  68.       FHead    : PaaBTNode;
  69.     protected
  70.       function btLevelOrder(aAction : TaaProcessNode;
  71.                             aExtraData : pointer) : PaaBTNode;
  72.       function btNoRecInOrder(aAction : TaaProcessNode;
  73.                               aExtraData : pointer) : PaaBTNode;
  74.       function btNoRecPostOrder(aAction : TaaProcessNode;
  75.                                 aExtraData : pointer) : PaaBTNode;
  76.       function btNoRecPreOrder(aAction : TaaProcessNode;
  77.                                aExtraData : pointer) : PaaBTNode;
  78.       function btRecInOrder(aNode   : PaaBTNode;
  79.                             aAction : TaaProcessNode;
  80.                             aExtraData : pointer) : PaaBTNode;
  81.       function btRecPostOrder(aNode   : PaaBTNode;
  82.                               aAction : TaaProcessNode;
  83.                               aExtraData : pointer) : PaaBTNode;
  84.       function btRecPreOrder(aNode   : PaaBTNode;
  85.                              aAction : TaaProcessNode;
  86.                              aExtraData : pointer) : PaaBTNode;
  87.     public
  88.       constructor Create(aDisposeItem : TaaDisposeItem);
  89.       destructor Destroy; override;
  90.  
  91.       procedure Clear;
  92.       procedure Delete(aNode : PaaBTNode);
  93.       function InsertAt(aParentNode  : PaaBTNode;
  94.                         aAsLeftChild : boolean;
  95.                         aItem        : pointer) : PaaBTNode;
  96.       function Root : PaaBTNode;
  97.       function Traverse(aMode         : TaaTraversalMode;
  98.                         aAction       : TaaProcessNode;
  99.                         aExtraData    : pointer;
  100.                         aUseRecursion : boolean) : PaaBTNode;
  101.  
  102.       property Count : integer read FCount;
  103.   end;
  104.  
  105.   TaaBinarySearchTree = class     {binary search tree class}
  106.     private
  107.       FBinTree : TaaBinaryTree;
  108.       FCompare : TaaCompareFunction;
  109.       FCount   : integer;
  110.     protected
  111.       function bstFindItem(aItem    : pointer;
  112.                        var aNode    : PaaBTNode;
  113.                        var aUseLeft : boolean) : boolean;
  114.       function bstFindNodeToDelete(aItem : pointer) : PaaBTNode;
  115.       function bstInsertPrim(aItem    : pointer;
  116.                          var aUseLeft : boolean) : PaaBTNode;
  117.     public
  118.       constructor Create(aCompare : TaaCompareFunction;
  119.                          aDispose : TaaDisposeItem);
  120.       destructor Destroy; override;
  121.  
  122.       procedure Clear;
  123.       procedure Delete(aItem : pointer); virtual;
  124.       function Find(aKeyItem : pointer) : pointer;
  125.       procedure Insert(aItem : pointer); virtual;
  126.       function Traverse(aMode         : TaaTraversalMode;
  127.                         aAction       : TaaProcessNode;
  128.                         aExtraData    : pointer;
  129.                         aUseRecursion : boolean) : pointer;
  130.  
  131.       property Count : integer read FCount;
  132.       property BinaryTree : TaaBinaryTree read FBinTree;
  133.   end;
  134.  
  135.   TaaRedBlackTree = class(TaaBinarySearchTree)  {red-black tree class}
  136.     private
  137.     protected
  138.       function rbtPromote(aNode  : PaaBTNode) : PaaBTNode;
  139.     public
  140.       procedure Delete(aItem : pointer); override;
  141.       procedure Insert(aItem : pointer); override;
  142.   end;
  143.  
  144. type
  145.   TaaDrawBinaryNode = procedure (aNode  : PaaBTNode;
  146.                                  aStrip : integer;
  147.                                  aColumn: integer;
  148.                                  aParentStrip : integer;
  149.                                  aParentColumn: integer;
  150.                                  aExtraData   : pointer);
  151.  
  152. procedure DrawBinaryTree(aTree      : TObject;
  153.                          aDrawNode  : TaaDrawBinaryNode;
  154.                          aExtraData : pointer);
  155.  
  156. implementation
  157.  
  158. uses
  159.   AALnkLst;
  160.  
  161. {===NodeManager for binary tree nodes================================}
  162. type
  163.   PnmPage = ^TnmPage;
  164.   TnmPage = packed record
  165.     nmpNext  : PnmPage;
  166.     nmpNodes : array [0..pred(PageNodeCount)] of TaaBTNode;
  167.   end;
  168. {--------}
  169. var
  170.   nmFreeList : PaaBTNode;
  171.   nmPageList : PnmPage;
  172. {--------}
  173. procedure nmFreeNode(aNode : PaaBTNode);
  174. begin
  175.   {$IFDEF UseNodeManager}
  176.   {add the node to the top of the free list}
  177.   aNode^.btParent := nmFreeList;
  178.   nmFreeList := aNode;
  179.   {$ELSE}
  180.   Dispose(aNode);
  181.   {$ENDIF}
  182. end;
  183. {--------}
  184. procedure nmAllocPage;
  185. var
  186.   NewPage : PnmPage;
  187.   i       : integer;
  188. begin
  189.   {get a new page}
  190.   New(NewPage);
  191.   {add it to the current list of pages}
  192.   NewPage^.nmpNext := nmPageList;
  193.   nmPageList := NewPage;
  194.   {add all the nodes on the page to the free list}
  195.   for i := 0 to pred(PageNodeCount) do
  196.     nmFreeNode(@NewPage^.nmpNodes[i]);
  197. end;
  198. {--------}
  199. function nmAllocNode : PaaBTNode;
  200. begin
  201.   {$IFDEF UseNodeManager}
  202.   {if the free list is empty, allocate a new page of nodes}
  203.   if (nmFreeList = nil) then
  204.     nmAllocPage;
  205.   {return the first node on the free list}
  206.   Result := nmFreeList;
  207.   nmFreeList := Result^.btParent;
  208.   {$ELSE}
  209.   New(Result);
  210.   {$ENDIF}
  211.   {$IFDEF InDebugMode}
  212.   Result^.btParent := nil;
  213.   Result^.btChild[aaLeft] := nil;
  214.   Result^.btChild[aaRight] := nil;
  215.   Result^.btData := nil;
  216.   Result^.btExtra := 0;
  217.   {$ENDIF}
  218. end;
  219. {====================================================================}
  220.  
  221.  
  222. {===Helper routines==================================================}
  223. function DisposeNode(aNode      : PaaBTNode;
  224.                      aExtraData : pointer) : boolean; far;
  225. var
  226.   DisposeItem : TaaDisposeItem absolute aExtraData;
  227. begin
  228.   if (aExtraData <> nil) then
  229.     DisposeItem(aNode^.btData);
  230.   nmFreeNode(aNode);
  231.   Result := true;
  232. end;
  233. {====================================================================}
  234.  
  235.  
  236. {===TaaBinaryTree====================================================}
  237. constructor TaaBinaryTree.Create(aDisposeItem : TaaDisposeItem);
  238. begin
  239.   inherited Create;
  240.   FDispose := aDisposeItem;
  241.   {allocate a head node, eventually the root node of the tree will be
  242.    its left child}
  243.   FHead := nmAllocNode;
  244.   FHead^.btParent := nil;
  245.   FHead^.btChild[aaLeft] := nil;
  246.   FHead^.btChild[aaRight] := nil;
  247.   FHead^.btData := nil;
  248.   FHead^.btExtra := 0;
  249. end;
  250. {--------}
  251. destructor TaaBinaryTree.Destroy;
  252. begin
  253.   Clear;
  254.   nmFreeNode(FHead);
  255.   inherited Destroy;
  256. end;
  257. {--------}
  258. function TaaBinaryTree.btLevelOrder(aAction : TaaProcessNode;
  259.                                     aExtraData : pointer) : PaaBTNode;
  260. var
  261.   Queue : TaaQueue;
  262.   Node  : PaaBTNode;
  263. begin
  264.   {assume we won't get a node selected}
  265.   Result := nil;
  266.   {simple case first}
  267.   if (FCount = 0) then
  268.     Exit;
  269.   {create the queue}
  270.   Queue := TaaQueue.Create;
  271.   try
  272.     {enqueue the root}
  273.     Queue.Enqueue(FHead^.btChild[aaLeft]);
  274.     {continue until the queue is empty}
  275.     while not Queue.IsEmpty do begin
  276.       {get the node at the head of the queue}
  277.       Node := Queue.Dequeue;
  278.       {perform the action on it, if this returns false (ie, don't
  279.        continue), return this node}
  280.       if not aAction(Node, aExtraData) then begin
  281.         Result := Node;
  282.         Queue.Clear;
  283.       end
  284.       {otherwise, continue}
  285.       else begin
  286.         {enqueue the left child, if it's not nil}
  287.         if (Node^.btChild[aaLeft] <> nil) then
  288.           Queue.Enqueue(Node^.btChild[aaLeft]);
  289.         {enqueue the right child, if it's not nil}
  290.         if (Node^.btChild[aaRight] <> nil) then
  291.           Queue.Enqueue(Node^.btChild[aaRight]);
  292.       end;
  293.     end;
  294.   finally
  295.     {destroy the queue}
  296.     Queue.Free;
  297.   end;
  298. end;
  299. {--------}
  300. function TaaBinaryTree.btNoRecInOrder(aAction : TaaProcessNode;
  301.                                       aExtraData : pointer) : PaaBTNode;
  302. var
  303.   Stack : TaaStack;
  304.   Node  : PaaBTNode;
  305. begin
  306.   {assume we won't get a node selected}
  307.   Result := nil;
  308.   {simple case first}
  309.   if (FCount = 0) then
  310.     Exit;
  311.   {create the stack}
  312.   Stack := TaaStack.Create;
  313.   try
  314.     {push the root}
  315.     Stack.Push(FHead^.btChild[aaLeft]);
  316.     {continue until the stack is empty}
  317.     while not Stack.IsEmpty do begin
  318.       {get the node at the head of the queue}
  319.       Node := Stack.Pop;
  320.       {if it's nil, pop the next node, perform the action on it, if
  321.        this returns false (ie, don't continue), return this node}
  322.       if (Node = nil) then begin
  323.         Node := Stack.Pop;
  324.         if not aAction(Node, aExtraData) then begin
  325.           Result := Node;
  326.           Stack.Clear;
  327.         end;
  328.       end
  329.       {otherwise, the children of the node have not been pushed yet}
  330.       else begin
  331.         {push the right child, if it's not nil}
  332.         if (Node^.btChild[aaRight] <> nil) then
  333.           Stack.Push(Node^.btChild[aaRight]);
  334.         {push the node, followed by a nil pointer}
  335.         Stack.Push(Node);
  336.         Stack.Push(nil);
  337.         {push the left child, if it's not nil}
  338.         if (Node^.btChild[aaLeft] <> nil) then
  339.           Stack.Push(Node^.btChild[aaLeft]);
  340.       end;
  341.     end;
  342.   finally
  343.     {destroy the stack}
  344.     Stack.Free;
  345.   end;
  346. end;
  347. {--------}
  348. function TaaBinaryTree.btNoRecPostOrder(aAction : TaaProcessNode;
  349.                                         aExtraData : pointer) : PaaBTNode;
  350. var
  351.   Stack : TaaStack;
  352.   Node  : PaaBTNode;
  353. begin
  354.   {assume we won't get a node selected}
  355.   Result := nil;
  356.   {simple case first}
  357.   if (FCount = 0) then
  358.     Exit;
  359.   {create the stack}
  360.   Stack := TaaStack.Create;
  361.   try
  362.     {push the root}
  363.     Stack.Push(FHead^.btChild[aaLeft]);
  364.     {continue until the stack is empty}
  365.     while not Stack.IsEmpty do begin
  366.       {get the node at the head of the queue}
  367.       Node := Stack.Pop;
  368.       {if it's nil, pop the next node, perform the action on it, if
  369.        this returns false (ie, don't continue), return this node}
  370.       if (Node = nil) then begin
  371.         Node := Stack.Pop;
  372.         if not aAction(Node, aExtraData) then begin
  373.           Result := Node;
  374.           Stack.Clear;
  375.         end;
  376.       end
  377.       {otherwise, the children of the node have not been pushed yet}
  378.       else begin
  379.         {push the node, followed by a nil pointer}
  380.         Stack.Push(Node);
  381.         Stack.Push(nil);
  382.         {push the right child, if it's not nil}
  383.         if (Node^.btChild[aaRight] <> nil) then
  384.           Stack.Push(Node^.btChild[aaRight]);
  385.         {push the left child, if it's not nil}
  386.         if (Node^.btChild[aaLeft] <> nil) then
  387.           Stack.Push(Node^.btChild[aaLeft]);
  388.       end;
  389.     end;
  390.   finally
  391.     {destroy the stack}
  392.     Stack.Free;
  393.   end;
  394. end;
  395. {--------}
  396. function TaaBinaryTree.btNoRecPreOrder(aAction : TaaProcessNode;
  397.                                        aExtraData : pointer) : PaaBTNode;
  398. var
  399.   Stack : TaaStack;
  400.   Node  : PaaBTNode;
  401. begin
  402.   {assume we won't get a node selected}
  403.   Result := nil;
  404.   {simple case first}
  405.   if (FCount = 0) then
  406.     Exit;
  407.   {create the stack}
  408.   Stack := TaaStack.Create;
  409.   try
  410.     {push the root}
  411.     Stack.Push(FHead^.btChild[aaLeft]);
  412.     {continue until the stack is empty}
  413.     while not Stack.IsEmpty do begin
  414.       {get the node at the head of the queue}
  415.       Node := Stack.Pop;
  416.       {perform the action on it, if this returns false (ie, don't
  417.        continue), return this node}
  418.       if not aAction(Node, aExtraData) then begin
  419.         Result := Node;
  420.         Stack.Clear;
  421.       end
  422.       {otherwise, continue}
  423.       else begin
  424.         {push the right child, if it's not nil}
  425.         if (Node^.btChild[aaRight] <> nil) then
  426.           Stack.Push(Node^.btChild[aaRight]);
  427.         {push the left child, if it's not nil}
  428.         if (Node^.btChild[aaLeft] <> nil) then
  429.           Stack.Push(Node^.btChild[aaLeft]);
  430.       end;
  431.     end;
  432.   finally
  433.     {destroy the stack}
  434.     Stack.Free;
  435.   end;
  436. end;
  437. {--------}
  438. function TaaBinaryTree.btRecInOrder(aNode   : PaaBTNode;
  439.                                     aAction : TaaProcessNode;
  440.                                     aExtraData : pointer) : PaaBTNode;
  441. begin
  442.   Result := nil;
  443.   if (aNode^.btChild[aaLeft] <> nil) then begin
  444.     Result := btRecInOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  445.     if (Result <> nil) then Exit;
  446.   end;
  447.   if not aAction(aNode, aExtraData) then begin
  448.     Result := aNode;
  449.     Exit;
  450.   end;
  451.   if (aNode^.btChild[aaRight] <> nil) then begin
  452.     Result := btRecInOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  453.   end;
  454. end;
  455. {--------}
  456. function TaaBinaryTree.btRecPostOrder(aNode   : PaaBTNode;
  457.                                       aAction : TaaProcessNode;
  458.                                       aExtraData : pointer) : PaaBTNode;
  459. begin
  460.   Result := nil;
  461.   if (aNode^.btChild[aaLeft] <> nil) then begin
  462.     Result := btRecPostOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  463.     if (Result <> nil) then Exit;
  464.   end;
  465.   if (aNode^.btChild[aaRight] <> nil) then begin
  466.     Result := btRecPostOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  467.     if (Result <> nil) then Exit;
  468.   end;
  469.   if not aAction(aNode, aExtraData) then begin
  470.     Result := aNode;
  471.   end;
  472. end;
  473. {--------}
  474. function TaaBinaryTree.btRecPreOrder(aNode   : PaaBTNode;
  475.                                      aAction : TaaProcessNode;
  476.                                      aExtraData : pointer) : PaaBTNode;
  477. begin
  478.   Result := nil;
  479.   if not aAction(aNode, aExtraData) then begin
  480.     Result := aNode;
  481.     Exit;
  482.   end;
  483.   if (aNode^.btChild[aaLeft] <> nil) then begin
  484.     Result := btRecPreOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  485.     if (Result <> nil) then Exit;
  486.   end;
  487.   if (aNode^.btChild[aaRight] <> nil) then begin
  488.     Result := btRecPreOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  489.   end;
  490. end;
  491. {--------}
  492. procedure TaaBinaryTree.Clear;
  493. begin
  494.   {to clear a binary tree, we perform a postorder traversal, with the
  495.    action on each node being its disposal}
  496.   btNoRecPostOrder(DisposeNode, @FDispose);
  497.   FCount := 0;
  498.   FHead^.btChild[aaLeft] := nil;
  499. end;
  500. {--------}
  501. procedure TaaBinaryTree.Delete(aNode : PaaBTNode);
  502. var
  503.   HaveLeftChild : boolean;
  504.   AmLeftChild   : boolean;
  505. begin
  506.   if (aNode = nil)then
  507.     raise Exception.Create('TaaBinaryTree.Delete: node is nil');
  508.   {find out whether we have a single child and which one it is; if we
  509.    find that there are two children raise an exception}
  510.   if (aNode.btChild[aaLeft] <> nil) then begin
  511.     if (aNode.btChild[aaRight] <> nil) then
  512.       raise Exception.Create(
  513.           'TaaBinaryTree.Delete: cannot delete this node');
  514.     HaveLeftChild := true;
  515.   end
  516.   else
  517.     HaveLeftChild := false;
  518.   {find out whether we're a left or right child of our parent}
  519.   AmLeftChild := aNode^.btParent^.btChild[aaLeft] = aNode;
  520.   {set the child link of our parent to our child link}
  521.   aNode^.btParent^.btChild[AmLeftChild] :=
  522.      aNode^.btChild[HaveLeftChild];
  523.   if (aNode^.btChild[HaveLeftChild] <> nil) then
  524.     aNode^.btChild[HaveLeftChild]^.btParent := aNode^.btParent;
  525.   {free the node}
  526.   if Assigned(FDispose) then
  527.     FDispose(aNode^.btData);
  528.   nmFreeNode(aNode);
  529.   dec(FCount);
  530. end;
  531. {--------}
  532. function TaaBinaryTree.InsertAt(aParentNode  : PaaBTNode;
  533.                                 aAsLeftChild : boolean;
  534.                                 aItem        : pointer) : PaaBTNode;
  535. begin
  536.   {if the parent node is nil, assume this is inserting the root}
  537.   if (aParentNode = nil) then begin
  538.     aParentNode := FHead;
  539.     aAsLeftChild := true;
  540.   end;
  541.   {check to see the child link isn't already set}
  542.   if (aParentNode^.btChild[aAsLeftChild] <> nil) then
  543.     raise Exception.Create('TaaBinaryTree.InsertAt: cannot insert here');
  544.   {allocate a new node and insert as the required child of the parent}
  545.   Result := nmAllocNode;
  546.   Result^.btParent := aParentNode;
  547.   Result^.btChild[aaLeft] := nil;
  548.   Result^.btChild[aaRight] := nil;
  549.   Result^.btData := aItem;
  550.   Result^.btExtra := 0;
  551.   aParentNode^.btChild[aAsLeftChild] := Result;
  552.   inc(FCount);
  553. end;
  554. {--------}
  555. function TaaBinaryTree.Root : PaaBTNode;
  556. begin
  557.   Result := FHead^.btChild[aaLeft];
  558. end;
  559. {--------}
  560. function TaaBinaryTree.Traverse(aMode         : TaaTraversalMode;
  561.                                 aAction       : TaaProcessNode;
  562.                                 aExtraData    : pointer;
  563.                                 aUseRecursion : boolean) : PaaBTNode;
  564. begin
  565.   Result := nil;
  566.   if (FHead^.btChild[aaLeft] <> nil) then begin
  567.     case aMode of
  568.       tmPreOrder :
  569.         if aUseRecursion then 
  570.           Result := btRecPreOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  571.         else
  572.           Result := btNoRecPreOrder(aAction, aExtraData);
  573.       tmInOrder :
  574.         if aUseRecursion then
  575.           Result := btRecInOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  576.         else
  577.           Result := btNoRecInOrder(aAction, aExtraData);
  578.       tmPostOrder :
  579.         if aUseRecursion then
  580.           Result := btRecPostOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  581.         else
  582.           Result := btNoRecPostOrder(aAction, aExtraData);
  583.       tmLevelOrder :
  584.         Result := btLevelOrder(aAction, aExtraData);
  585.     end;
  586.   end;
  587. end;
  588. {====================================================================}
  589.  
  590.  
  591. {===TaaBinarySearchTree==============================================}
  592. constructor TaaBinarySearchTree.Create(aCompare : TaaCompareFunction;
  593.                                        aDispose : TaaDisposeItem);
  594. begin
  595.   inherited Create;
  596.   FCompare := aCompare;
  597.   FBinTree := TaaBinaryTree.Create(aDispose);
  598. end;
  599. {--------}
  600. destructor TaaBinarySearchTree.Destroy;
  601. begin
  602.   FBinTree.Free;
  603.   inherited Destroy;
  604. end;
  605. {--------}
  606. function TaaBinarySearchTree.bstFindItem(aItem    : pointer;
  607.                                      var aNode    : PaaBTNode;
  608.                                      var aUseLeft : boolean) : boolean;
  609. var
  610.   Walker : PaaBTNode;
  611.   CmpResult : integer;
  612. begin
  613.   Result := false;
  614.   if (FCount = 0) then begin
  615.     aNode := nil;
  616.     aUseLeft := true;
  617.     Exit;
  618.   end;
  619.   Walker := FBinTree.Root;
  620.   CmpResult := FCompare(aItem, Walker^.btData);
  621.   while (CmpResult <> 0) do begin
  622.     if (CmpResult < 0) then begin
  623.       if (Walker^.btChild[aaLeft] = nil) then begin
  624.         aNode := Walker;
  625.         aUseLeft := true;
  626.         Exit;
  627.       end;
  628.       Walker := Walker^.btChild[aaLeft];
  629.     end
  630.     else begin
  631.       if (Walker^.btChild[aaRight] = nil) then begin
  632.         aNode := Walker;
  633.         aUseLeft := false;
  634.         Exit;
  635.       end;
  636.       Walker := Walker^.btChild[aaRight];
  637.     end;
  638.     CmpResult := FCompare(aItem, Walker^.btData);
  639.   end;
  640.   Result := true;
  641.   aNode := Walker;
  642. end;
  643. {--------}
  644. function TaaBinarySearchTree.bstFindNodeToDelete(aItem : pointer) : PaaBTNode;
  645. var
  646.   Walker  : PaaBTNode;
  647.   Node    : PaaBTNode;
  648.   UseLeft : boolean;
  649.   Temp    : pointer;
  650. begin
  651.   {attempt to find the item; signal error if not found}
  652.   if not bstFindItem(aItem, Node, UseLeft) then
  653.     raise Exception.Create('TaaBinarySearchTree.Delete: item not found');
  654.   {if the node has two children, find the largest node that is smaller
  655.    than the one we want to delete, and swap over the items}
  656.   if (Node^.btChild[aaLeft] <> nil) and
  657.      (Node^.btChild[aaRight] <> nil) then begin
  658.     Walker := Node^.btChild[aaLeft];
  659.     while (Walker^.btChild[aaRight] <> nil) do
  660.       Walker := Walker^.btChild[aaRight];
  661.     Temp := Walker^.btData;
  662.     Walker^.btData := Node^.btData;
  663.     Node^.btData := Temp;
  664.     Node := Walker;
  665.   end;
  666.   {return the node to delete}
  667.   Result := Node;
  668. end;
  669. {--------}
  670. function TaaBinarySearchTree.bstInsertPrim(aItem    : pointer;
  671.                                        var aUseLeft : boolean) : PaaBTNode;
  672. begin
  673.   {first, attempt to find the item; if found, it's an error}
  674.   if bstFindItem(aItem, Result, aUseLeft) then
  675.     raise Exception.Create(
  676.        'TaaBinarySearchTree.bstInsertPrim: duplicate keys not allowed');
  677.   {this returns a node, so insert there}
  678.   Result := FBinTree.InsertAt(Result, aUseLeft, aItem);
  679.   inc(FCount);
  680. end;
  681. {--------}
  682. procedure TaaBinarySearchTree.Clear;
  683. begin
  684.   FBinTree.Clear;
  685.   FCount := 0;
  686. end;
  687. {--------}
  688. procedure TaaBinarySearchTree.Delete(aItem : pointer);
  689. begin
  690.   {delete the node}
  691.   FBinTree.Delete(bstFindNodeToDelete(aItem));
  692.   dec(FCount);
  693. end;
  694. {--------}
  695. function TaaBinarySearchTree.Find(aKeyItem : pointer) : pointer;
  696. var
  697.   Node : PaaBTNode;
  698.   UseLeft : boolean;
  699. begin
  700.   if bstFindItem(aKeyItem, Node, UseLeft) then
  701.     Result := Node^.btData
  702.   else
  703.     Result := nil;
  704. end;
  705. {--------}
  706. procedure TaaBinarySearchTree.Insert(aItem : pointer);
  707. var
  708.   UseLeft : boolean;
  709. begin
  710.   bstInsertPrim(aItem, UseLeft);
  711. end;
  712. {--------}
  713. function TaaBinarySearchTree.Traverse(aMode         : TaaTraversalMode;
  714.                                       aAction       : TaaProcessNode;
  715.                                       aExtraData    : pointer;
  716.                                       aUseRecursion : boolean) : pointer;
  717. var
  718.   Node : PaaBTNode;
  719. begin
  720.   Node := FBinTree.Traverse(aMode, aAction, aExtraData, aUseRecursion);
  721.   if (Node = nil) then
  722.     Result := nil
  723.   else
  724.     Result := Node^.btData;
  725. end;
  726. {====================================================================}
  727.  
  728.  
  729. function IsRed(aNode : PaaBTNode) : boolean;
  730. begin
  731.   if (aNode = nil) then
  732.     Result := false
  733.   else
  734.     Result := aNode^.btColor = aaRed;
  735. end;
  736.  
  737.  
  738. {===TaaRedBlackTree==================================================}
  739. procedure TaaRedBlackTree.Delete(aItem : pointer);
  740. var
  741.   Node       : PaaBTNode;
  742.   Dad        : PaaBTNode;
  743.   Child      : PaaBTNode;
  744.   Brother    : PaaBTNode;
  745.   FarNephew  : PaaBTNode;
  746.   NearNephew : PaaBTNode;
  747.   IsBalanced : boolean;
  748.   IsLeftChild: boolean;
  749. begin
  750.   {find the node to delete; this node will have but one child}
  751.   Node := bstFindNodeToDelete(aItem);
  752.   {if the node is red, or is the root, delete it with impunity}
  753.   if (Node^.btColor = aaRed) or
  754.      (Node = FBinTree.Root) then begin
  755.     FBinTree.Delete(Node);
  756.     dec(FCount);
  757.     Exit;
  758.   end;
  759.   {if the node's only child is red, recolor the child black, and
  760.    delete the node}
  761.   if (Node^.btChild[aaLeft] = nil) then
  762.     Child := Node^.btChild[aaRight]
  763.   else
  764.     Child := Node^.btChild[aaLeft];
  765.   if IsRed(Child) then begin
  766.     Child^.btColor := aaBlack;
  767.     FBinTree.Delete(Node);
  768.     dec(FCount);
  769.     Exit;
  770.   end;
  771.   {at this point, the node we have to delete is Node, and we
  772.    know that Child is black (and also maybe nil!), the parent (ie,
  773.    Node) is black, and there is a grandparent (which will soon be the
  774.    parent); the parent's brother also exists because of the black node
  775.    rule}
  776.  
  777.   {if the Child is nil, we'll have to help the loop a little bit and
  778.    set the parent and brother and whether this child is a left child
  779.    or not}
  780.   if (Child = nil) then begin
  781.     Dad := Node^.btParent;
  782.     if (Node = Dad^.btChild[aaLeft]) then begin
  783.       IsLeftChild := true;
  784.       Brother := Dad^.btChild[aaRight];
  785.     end
  786.     else begin
  787.       IsLeftChild := false;
  788.       Brother := Dad^.btChild[aaLeft];
  789.     end;
  790.   end;
  791.   {delete the node we want to, we have no more need of it}
  792.   FBinTree.Delete(Node);
  793.   dec(FCount);
  794.   Node := Child;
  795.   {in a loop, continue applying the red-black deletion balancing
  796.    algorithms until the tree is balanced}
  797.   repeat
  798.     {assume we'll balance it this time}
  799.     IsBalanced := true;
  800.     {we are balanced if the node is the root, so assume it isn't}
  801.     if (Node <> FBinTree.Root) then begin
  802.       {get the parent and the brother}
  803.       if (Node <> nil) then begin
  804.         Dad := Node^.btParent;
  805.         if (Node = Dad^.btChild[aaLeft]) then begin
  806.           IsLeftChild := true;
  807.           Brother := Dad^.btChild[aaRight];
  808.         end
  809.         else begin
  810.           IsLeftChild := false;
  811.           Brother := Dad^.btChild[aaLeft];
  812.         end;
  813.       end;
  814.       {we need a black brother, so if the brother is currently red,
  815.        color the parent red, the brother black, and promote the brother;
  816.        then go round loop again}
  817.       if (Brother^.btColor = aaRed) then begin
  818.         Dad^.btColor := aaRed;
  819.         Brother^.btColor := aaBlack;
  820.         rbtPromote(Brother);
  821.         IsBalanced := false;
  822.       end
  823.       {otherwise the brother is black}
  824.       else begin
  825.         {get the nephews}
  826.         if IsLeftChild then begin
  827.           FarNephew := Brother^.btChild[aaRight];
  828.           NearNephew := Brother^.btChild[aaLeft];
  829.         end
  830.         else begin
  831.           FarNephew := Brother^.btChild[aaLeft];
  832.           NearNephew := Brother^.btChild[aaRight];
  833.         end;
  834.         {if the far nephew is red (note that it could be nil!), color
  835.          it black, color the brother the same as the parent, color the
  836.          parent black, and then promote the brother; we're then done}
  837.         if IsRed(FarNephew) then begin
  838.           FarNephew^.btColor := aaBlack;
  839.           Brother^.btColor := Dad^.btColor;
  840.           Dad^.btColor := aaBlack;
  841.           rbtPromote(Brother);
  842.         end
  843.         {otherwise the far nephew is black}
  844.         else begin
  845.           {if the near nephew is red (note that it could be nil!), color
  846.            it the same color as the parent, color the parent black, and
  847.            zig-zag promote the nephew; we're then done}
  848.           if IsRed(NearNephew) then begin
  849.             NearNephew^.btColor := Dad^.btColor;
  850.             Dad^.btColor := aaBlack;
  851.             rbtPromote(rbtPromote(NearNephew));
  852.           end
  853.           {otherwise the near nephew is also black}
  854.           else begin
  855.             {if the parent is red, color it black and the brother red,
  856.              and we're done}
  857.             if (Dad^.btColor = aaRed) then begin
  858.               Dad^.btColor := aaBlack;
  859.               Brother^.btColor := aaRed;
  860.             end
  861.             {otherwise the parent is black: color the brother red and
  862.              start over with the parent}
  863.             else begin
  864.               Brother^.btColor := aaRed;
  865.               Node := Dad;
  866.               IsBalanced := false;
  867.             end;
  868.           end;
  869.         end;
  870.       end;
  871.     end;
  872.   until IsBalanced;
  873. end;
  874. {--------}
  875. procedure TaaRedBlackTree.Insert(aItem : pointer);
  876. var
  877.   Node    : PaaBTNode;
  878.   Dad     : PaaBTNode;
  879.   Grandad : PaaBTNode;
  880.   Uncle   : PaaBTNode;
  881.   IsLeftChild    : boolean;
  882.   DadIsLeftChild : boolean;
  883.   IsBalanced     : boolean;
  884. begin
  885.   {insert the new item, get back the node that was inserted and its
  886.    relationship to its parent}
  887.   Node := bstInsertPrim(aItem, IsLeftChild);
  888.  
  889.   {color it red}
  890.   Node^.btColor := aaRed;
  891.  
  892.   {in a loop, continue applying the red-black insertion balancing
  893.    algorithms until the tree is balanced}
  894.   repeat
  895.     {assume we'll balance it this time}
  896.     IsBalanced := true;
  897.     {if the node is the root, we're done and the tree is balanced, so
  898.      assume we're not at the root}
  899.     if (Node <> FBinTree.Root) then begin
  900.       {as we're not at the root, get the parent of this node}
  901.       Dad := Node^.btParent;
  902.       {if the parent is black, we're done and the tree is balanced, so
  903.        assume that the parent is red}
  904.       if (Dad^.btColor = aaRed) then begin
  905.         {if the parent is the root, just color it black and we're
  906.          done}
  907.         if (Dad = FBinTree.Root) then
  908.           Dad^.btColor := aaBlack
  909.         {otherwise the parent has a parent of its own}
  910.         else begin
  911.           {get the grandparent and color it red}
  912.           Grandad := Dad^.btParent;
  913.           Grandad^.btColor := aaRed;
  914.           {get the uncle node}
  915.           if (Grandad^.btChild[aaLeft] = Dad) then begin
  916.             DadIsLeftChild := true;
  917.             Uncle := Grandad^.btChild[aaRight];
  918.           end
  919.           else begin
  920.             DadIsLeftChild := false;
  921.             Uncle := Grandad^.btChild[aaLeft];
  922.           end;
  923.           {if the uncle is also red (note that the uncle can be nil!),
  924.            color the parent black, the uncle black and start over with
  925.            the grandparent}
  926.           if IsRed(Uncle) then begin
  927.             Dad^.btColor := aaBlack;
  928.             Uncle^.btColor := aaBlack;
  929.             Node := Grandad;
  930.             IsBalanced := false;
  931.           end
  932.           {otherwise the uncle is black}
  933.           else begin
  934.             {if the node we inserted has the same relationship with
  935.              its parent as the parent has with the grandparent, color
  936.              the parent black and promote it; we're then done}
  937.             IsLeftChild := Node = Dad^.btChild[aaLeft];
  938.             if IsLeftChild = DadIsLeftChild then begin
  939.               Dad^.btColor := aaBlack;
  940.               rbtPromote(Dad);
  941.             end
  942.             {otherwise color the node black and zig-zag promote it;
  943.              we're then done}
  944.             else begin
  945.               Node^.btColor := aaBlack;
  946.               rbtPromote(rbtPromote(Node));
  947.             end;
  948.           end;
  949.         end;
  950.       end;
  951.     end;
  952.   until IsBalanced;
  953. end;
  954. {--------}
  955. function TaaRedBlackTree.rbtPromote(aNode  : PaaBTNode) : PaaBTNode;
  956. var
  957.   Parent : PaaBTNode;
  958. begin
  959.   {make a note of the parent of the node we're promoting}
  960.   Parent := aNode^.btParent;
  961.  
  962.   {in both cases there are 6 links to be broken and remade: the node's
  963.    link to its child and vice versa, the node's link with its parent
  964.    and vice versa and the parent's link with its parent and vice
  965.    versa; note that the node's child could be nil}
  966.  
  967.   {promote a left child = right rotation of parent}
  968.   if (Parent^.btChild[aaLeft] = aNode) then begin
  969.     Parent^.btChild[aaLeft] := aNode^.btChild[aaRight];
  970.     if (Parent^.btChild[aaLeft] <> nil) then
  971.       Parent^.btChild[aaLeft]^.btParent := Parent;
  972.     aNode^.btParent := Parent^.btParent;
  973.     if (aNode^.btParent^.btChild[aaLeft] = Parent) then
  974.       aNode^.btParent^.btChild[aaLeft] := aNode
  975.     else
  976.       aNode^.btParent^.btChild[aaRight] := aNode;
  977.     aNode^.btChild[aaRight] := Parent;
  978.     Parent^.btParent := aNode;
  979.   end
  980.   {promote a right child = left rotation of parent}
  981.   else begin
  982.     Parent^.btChild[aaRight] := aNode^.btChild[aaLeft];
  983.     if (Parent^.btChild[aaRight] <> nil) then
  984.       Parent^.btChild[aaRight]^.btParent := Parent;
  985.     aNode^.btParent := Parent^.btParent;
  986.     if (aNode^.btParent^.btChild[aaLeft] = Parent) then
  987.       aNode^.btParent^.btChild[aaLeft] := aNode
  988.     else
  989.       aNode^.btParent^.btChild[aaRight] := aNode;
  990.     aNode^.btChild[aaLeft] := Parent;
  991.     Parent^.btParent := aNode;
  992.   end;
  993.   {return the node we promoted}
  994.   Result := aNode;
  995. end;
  996. {====================================================================}
  997.  
  998.  
  999. {===Drawing a binary tree============================================}
  1000. type
  1001.   PNodePosn = ^TNodePosn;
  1002.   TNodePosn = packed record
  1003.     npStrip  : integer;
  1004.     npColumn : integer;
  1005.   end;
  1006. {--------}
  1007. procedure DrawBinaryTree(aTree      : TObject;
  1008.                          aDrawNode  : TaaDrawBinaryNode;
  1009.                          aExtraData : pointer);
  1010.   {------}
  1011.   function GenPosNode(aNode   : PaaBTNode;
  1012.                       aStrip  : integer;
  1013.                   var aColumn : integer) : PaaBTNode;
  1014.   var
  1015.     OurPosNode : PaaBTNode;
  1016.     OurPosition : PNodePosn;
  1017.   begin
  1018.     {allocate ourselves a node and a position}
  1019.     OurPosNode := nmAllocNode;
  1020.     FillChar(OurPosNode^, sizeof(OurPosNode^), 0);
  1021.     New(OurPosition);
  1022.     OurPosNode^.btData := OurPosition;
  1023.  
  1024.     {visit the left subtree}
  1025.     if (aNode^.btChild[aaLeft] <> nil) then begin
  1026.       OurPosNode^.btChild[aaLeft] :=
  1027.          GenPosNode(aNode^.btChild[aaLeft], succ(aStrip), aColumn);
  1028.       OurPosNode^.btChild[aaLeft]^.btParent := OurPosNode;
  1029.     end;
  1030.  
  1031.     {store our position, increment the column since we're there now}
  1032.     OurPosition^.npStrip := aStrip;
  1033.     OurPosition^.npColumn := aColumn;
  1034.     inc(aColumn);
  1035.  
  1036.     {visit the right subtree}
  1037.     if (aNode^.btChild[aaRight] <> nil) then begin
  1038.       OurPosNode^.btChild[aaRight] :=
  1039.         GenPosNode(aNode^.btChild[aaRight], succ(aStrip), aColumn);
  1040.       OurPosNode^.btChild[aaRight]^.btParent := OurPosNode;
  1041.     end;
  1042.  
  1043.     Result := OurPosNode;
  1044.   end;
  1045.   {------}
  1046.   procedure DestroyPosNode(aNode : PaaBTNode);
  1047.   begin
  1048.     {destroy the left subtree}
  1049.     if (aNode^.btChild[aaLeft] <> nil) then
  1050.       DestroyPosNode(aNode^.btChild[aaLeft]);
  1051.     {destroy the right subtree}
  1052.     if (aNode^.btChild[aaRight] <> nil) then
  1053.       DestroyPosNode(aNode^.btChild[aaRight]);
  1054.     {destroy this node}
  1055.     Dispose(PNodePosn(aNode^.btData));
  1056.     nmFreeNode(aNode);
  1057.   end;
  1058.   {------}
  1059. var
  1060.   BinTree : TaaBinaryTree;
  1061.   Strip, Column : integer;
  1062.   PStrip, PColumn : integer;
  1063.   PosRoot : PaaBTNode;
  1064.   Queue   : TaaQueue;
  1065.   Node    : PaaBTNode;
  1066.   PosNode : PaaBTNode;
  1067. begin
  1068.   {get a hold of the actual binary tree}
  1069.   if (aTree is TaaBinaryTree) then
  1070.     BinTree := TaaBinaryTree(aTree)
  1071.   else if (aTree is TaaBinarySearchTree) then
  1072.     BinTree := TaaBinarySearchTree(aTree).BinaryTree
  1073.   else
  1074.     Exit;
  1075.  
  1076.   {simple case first}
  1077.   if (BinTree.Count = 0) then
  1078.     Exit;
  1079.  
  1080.   {--first pass--}
  1081.   Strip := 0;
  1082.   Column := 0;
  1083.   PosRoot := GenPosNode(BinTree.Root, Strip, Column);
  1084.  
  1085.   {--second pass--}
  1086.   try
  1087.     {create the queue}
  1088.     Queue := TaaQueue.Create;
  1089.     try
  1090.       {enqueue the roots}
  1091.       Queue.Enqueue(BinTree.Root);
  1092.       Queue.Enqueue(PosRoot);
  1093.       {continue until the queue is empty}
  1094.       while not Queue.IsEmpty do begin
  1095.         {get the nodes at the head of the queue}
  1096.         Node := Queue.Dequeue;
  1097.         PosNode := Queue.Dequeue;
  1098.         {draw the node}
  1099.         if (PosNode = PosRoot) then begin
  1100.           PStrip := -1;
  1101.           PColumn := -1;
  1102.         end
  1103.         else with PNodePosn(PosNode^.btParent^.btData)^ do begin
  1104.           PStrip := npStrip;
  1105.           PColumn := npColumn;
  1106.         end;
  1107.         with PNodePosn(PosNode^.btData)^ do
  1108.           aDrawNode(Node, npStrip, npColumn,
  1109.                           PStrip, PColumn, aExtraData);
  1110.         {enqueue the left children, if the first is not nil}
  1111.         if (Node^.btChild[aaLeft] <> nil) then begin
  1112.           Queue.Enqueue(Node^.btChild[aaLeft]);
  1113.           Queue.Enqueue(PosNode^.btChild[aaLeft]);
  1114.         end;
  1115.         {enqueue the right children, if the first is not nil}
  1116.         if (Node^.btChild[aaRight] <> nil) then begin
  1117.           Queue.Enqueue(Node^.btChild[aaRight]);
  1118.           Queue.Enqueue(PosNode^.btChild[aaRight]);
  1119.         end;
  1120.       end;
  1121.     finally
  1122.       {destroy the queue}
  1123.       Queue.Free;
  1124.     end;
  1125.   finally
  1126.     {now destroy the position binary tree}
  1127.     DestroyPosNode(PosRoot);
  1128.   end;
  1129. end;
  1130. {====================================================================}
  1131.  
  1132.  
  1133. procedure FinalizeUnit; far;
  1134. var
  1135.   Temp : PnmPage;
  1136. begin
  1137.   {destroy all the single node pages}
  1138.   Temp := nmPageList;
  1139.   while (Temp <> nil) do begin
  1140.     nmPageList := Temp^.nmpNext;
  1141.     Dispose(Temp);
  1142.     Temp := nmPageList;
  1143.   end;
  1144. end;
  1145.  
  1146. initialization
  1147.   nmFreeList := nil;
  1148.   nmPageList := nil;
  1149.   {$IFDEF Windows}
  1150.   AddExitProc(FinalizeUnit);
  1151.   {$ENDIF}
  1152.  
  1153. {$IFDEF Win32}
  1154. finalization
  1155.   FinalizeUnit;
  1156. {$ENDIF}
  1157.  
  1158. end.
  1159.  
  1160.